<?php

class CTableModel extends CModel {

    public $db;
    public $tableName = '';
    public $primaryKey = 'id';
	public $createdCol = '';
	public $updatedCol = '';
	protected $_data = array();

	public function __construct($dsnName = 'master')
	{
        $this->db = CDb::getInstance();
        if (empty($this->tableName)) {
        	$modelName = substr(get_class($this), 1, -5);
            $this->tableName = strtolower($modelName);
        }
        $this->tableName = $this->db->tablePrefix . $this->tableName;
    }

    public function __set($name, $value)
    {
        $this->_data[$name] = $value;
    }
    
    public function __get($name)
    {
        return isset($this->_data[$name]) ? $this->_data[$name] : null;
    }

    public function __isset($name)
    {
        return isset($this->_data[$name]);
    }
    
    public function __unset($name)
    {
        unset($this->_data[$name]);
    }
    
	protected function _where($where = null)
	{
        if ($where) {
            if (is_array($where)) {
                $value = isset($where[1]) ? $where[1] : null;
                return array($where[0], $value);
            }
            if (is_numeric($where)) {
                return array($this->primaryKey . ' = ?', $where);
            }
            if (is_string($where)) {
                return array($where, null);
            }
        }
        return null;
	}

	protected function _find($fields = '*', $where = null, $order = '')
	{
        $sqlTpl = 'SELECT %s FROM %s';
        $sql = sprintf($sqlTpl, $fields, $this->tableName);
        $where = $this->_where($where);
		if ($where) {
			$sql = sprintf($sql . ' WHERE %s', $where[0]);
		}
		if ($order) {
            $sql = sprintf($sql . ' ORDER BY %s', $order);
		}
		return array('sql' => $sql, 'params' => (array) $where[1]);
	}

	public function limit($fields, $where, $order, $count = 10, $offset = 0)
	{
        $result = $this->_find($fields, $where, $order);
        return $this->db->selectLimit($result['sql'], $result['params'], (int) $count, (int) $offset);
	}
    
	public function findPage($page, $fields = '*', $where = null, $order = '', $pageSize = 10)
	{
        $page = ($page > 0) ? $page : 1;
        $offset = ($page - 1) * $pageSize;
        return $this->limit($fields, $where, $order, $pageSize, $offset);
	}
    
	public function findAll($fields = '*', $where = null, $order = '')
	{
        $result = $this->_find($fields, $where, $order);
        return $this->db->getAll($result['sql'], $result['params']);
	}

	public function findCol($field, $where = null, $order = '')
	{
        $result = $this->_find($field, $where, $order);
        return $this->db->getOne($result['sql'], $result['params']);
	}

	public function find($where = null, $fields = '*', $order = '')
	{
        $result = $this->_find($fields, $where, $order);
        $this->_data = $this->db->getRow($result['sql'], $result['params']);
        return $this->_data;
	}
    
	public function create($params = array())
	{
        if (!$params || !is_array($params)) {
            if ($this->_data && is_array($this->_data)) {
                $params = $this->_data;
            } else {
                return false;
            }
        }
        
		$sqlTpl = 'INSERT INTO %s (%s) VALUES (%s)';
		foreach ($params as $field => $value) {
			if ('unbind' == $field) {
                $args = explode('=', $value);
			    $fields[] = trim($args[0]);
			    $placeholders[] = trim($args[1]);
			} else {
			    $fields[] = $field;
			    $placeholders[] = '?';
			    $values[] = $value;
			}
		}
        if ($this->createdCol && !isset($fields[$this->createdCol])) {
            $fields[] = $this->createdCol;
            $placeholders[] = '?';
            $values[] = date('Y-m-d H:i:s', time());
        }
        if ($this->updatedCol && !isset($fields[$this->updatedCol])) {
            $fields[] = $this->updatedCol;
            $placeholders[] = '?';
            $values[] = date('Y-m-d H:i:s', time());
        }
		$sql = sprintf($sqlTpl, $this->tableName, implode(', ', $fields), implode(', ', $placeholders));

		$this->db->execute($sql, (array) $values);
		return $this->db->insertId();
		//$this->_data[$this->primaryKey] = $this->db->insertId();
        //return $this->_data[$this->primaryKey];
	}
    
	public function update($where, array $params)
	{
        if (isset($params[$this->primaryKey])) {
            unset($params[$this->primaryKey]);
        }
		$unbinds = array();
		$sqlTpl = 'UPDATE %s SET %s WHERE %s';
		foreach ($params as $field => $value) {
			if ('unbind' == $field) {
                $args = explode('=', $value);
				$unbinds[] = "{$value}";
                $allFields[] = trim($args[0]);
			} else {
				$fields[] = "{$field} = ?";
				$values[] = $value;
                $allFields[] = trim($field);
			}
		}
        if ($this->updatedCol && !isset($allFields[$this->updatedCol])) {
            $fields[] = $this->updatedCol . ' = ?';
            $values[] = date('Y-m-d H:i:s', time());
        }
		$strFields = implode(', ', (array) $fields);
		if (count($unbinds)) {
			$strFields .= (empty($strFields) ? '' : ', ') . implode(', ', (array) $unbinds);
		}
		$where = $this->_where($where);
		$sql = sprintf($sqlTpl, $this->tableName, $strFields, $where[0]);
        $values = array_merge((array) $values, (array) $where[1]);
        $this->unsetData();
		return $this->db->execute($sql, $values);
	}
	
	public function delete($where = null)
	{
        if (null === $where) {
            if (isset($this->_data[$this->primaryKey])) {
                $where = $this->_data[$this->primaryKey];
            } else {
                $this->unsetData();
                return 0;
            }
        }
        
		$sqlTpl = 'DELETE FROM %s WHERE %s';
        $where = $this->_where($where);
		$sql = sprintf($sqlTpl, $this->tableName, $where[0]);
        $this->unsetData();
		return $this->db->execute($sql, (array) $where[1]);
	}

    public function save($params = array())
    {
        $params = array_merge($this->_data, (array) $params);
        if (isset($params[$this->primaryKey])) {
            return $this->update($params[$this->primaryKey], $params);
        }
        $this->unsetData();
        return 0;
    }

    public function setData($params)
    {
        $this->_data = (array) $params;
    }
    
    public function getData()
    {
        return $this->_data;
    }

    public function unsetData()
    {
        $this->_data = array();
    }
}
